// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 * Description: M536a specific symbols
 * Author: Huawei OS Kernel Lab
 * Create: Mon May 23 19:17:11 2022
 */

#include <asm/bootparam.h>
#include <hmkernel/types.h>
#include <hongmeng/errno.h>

#include <libhmpm/cpuhp.h>
#include <libhmpm/shutdown.h>
#include <libhmsrv_sys/hm_init.h>
#include <libhmsrv_sys/hm_timer.h>
#include <libhmsrv_sys/hm_sysctrl.h>

#include <liblinux/pal.h>
#include <lnxbase/lnxbase.h>
#include <devhost/log.h>
#include "libdh_linux.h"

EXPORT_SYMBOL(liblinux_pal_get_unused_fd_flags);
EXPORT_SYMBOL(liblinux_pal_fd_install);
EXPORT_SYMBOL(liblinux_pal_put_unused_fd);

const struct boot_param param_m536a[] __section(".fixup.boot_param") = {
	/* ATTENTION: fw_devlink is very inefficient, set fw_devlink to off */
	{1, "fw_devlink", "off", 0},
};

void machine_emergency_restart(void)
{
	int ret;

	ret = hm_reboot(lnxbase_backend_args_find("reboot_reason"));
	if (ret < 0)
		dh_panic("hm_reboot failed err: %s\n", hmstrerror(ret));
}
EXPORT_SYMBOL(machine_emergency_restart);

static __u64 tocks_to_usec(__u64 tocks)
{
	int err;
	struct timespec ts;

	err = tocks_to_timespec(tocks, &ts);
	if (err < 0) {
		dh_error("tocks_to_timespec failed err: %s\n", hmstrerror(err));
		return -1ULL;
	}

	return ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
}

__u64 get_cpu_idle_time_us(int cpu, __u64 *total_time)
{
	int err;
	struct __sysctrl_cpu_stat stat = {0};
	__u64 tocks_idle;

	err = hm_sysctl_cpu_stat_of(cpu, &stat);
	if (err < 0) {
		dh_error("cpustat failed err: %s\n", hmstrerror(err));
		return -1ULL;
	}

	tocks_idle = stat.idle_time + stat.iowait_time;
	if (total_time != NULL)
		*total_time = tocks_to_usec(tocks_idle + stat.run_time +
					    stat.nice_time + stat.sys_time +
					    stat.irq_time);

	return tocks_to_usec(tocks_idle);
}
EXPORT_SYMBOL_GPL(get_cpu_idle_time_us);

__attribute__((weak))
int rtc_set_ntp_time(struct timespec64 now)
{
	return 0;
}

__attribute__((weak))
int pinctrl_init_done(struct device *dev)
{
	return 0;
}

__attribute__((weak))
int pinctrl_bind_pins(struct device *dev)
{
	return 0;
}

__attribute__((weak))
const struct iommu_ops *of_iommu_configure(struct device *dev,
				struct device_node *master_np)
{
	return NULL;
}

int liblinux_cpu_up(unsigned int cpu)
{
	return hm_cpu_up(cpu) ? -1 : 0;
}
EXPORT_SYMBOL(liblinux_cpu_up);

int liblinux_cpu_down(unsigned int cpu)
{
	return hm_cpu_down(cpu) ? -1 : 0;
}
EXPORT_SYMBOL(liblinux_cpu_down);

void liblinux_reboot(unsigned int flag, const char *reason)
{
	int ret;

	dh_info("reboot system, flag=%u, reason=%s\n", flag, reason ? reason : "<unknown>");
	ret = hminit_notify_reboot(reason, flag);
	if (ret != 0)
		dh_panic("hminit_notify_reboot failed, err=%s\n", hmstrerror(ret));
}
EXPORT_SYMBOL(liblinux_reboot);

void liblinux_shutdown(void)
{
	int ret;

	dh_info("shutdown system\n");
	ret = hminit_notify_shutdown();
	if (ret != 0)
		dh_panic("hminit_notify_shutdown failed, err=%s\n", hmstrerror(ret));
}
EXPORT_SYMBOL(liblinux_shutdown);
